就算知道應該測試,但如何測試又是一門學問。
在 Day 12:使用 PHPUnit 一文中,我提到了如何以 PHPUnit 這套 Framework 進行測試。
今天想對「測試」這件事進行一些淺談,絕對不是因為沒題材寫了。
就現代軟體開發而言,時常會衍生出許多新潮的名詞,然後會有一坨傳教士在外招攬信徒。
我認為所有的流派都有其優勢,但不建議一味相信,應該在實踐後自己去思量是否合適。
TDD,中文譯為「測試驅動開發」。
其特色「先寫測試,再寫程式」的思想打破一般軟體開發普遍的習慣,其優勢在於能夠靈活變化快速迭代的需求。
這樣的測試方式會先刻意讓測試失敗,然後為了讓測試成功所以去撰寫相應的程式。最終測試會全部通過,屆時就是完整符合需求的時候。
TDD 的思想核心是「碎步向前」,切分許多細碎的需求然後實踐之,之後構築一個龐大的系統。
BDD,中文譯為「行為驅動開發」。
BDD 分為 SpecBDD 與 StoryBDD:SpecBDD 比較類似單元測試;StoryBDD 比較類似於整合測試。
無論是 SpecBDD 或 StoryBDD,其提倡的思想都是「利用口語化的邏輯描述某件事的行為與其預期的結果」。
BDD 的優點在於,無論程式是如何實現,它的最後行為一定符合預期(否則不會通過測試)。然而缺點是如果頻繁變更需求,重寫 BDD 文件是件相當耗費心力的事。再者,因為只是「行為符合需求」所以其過程不一定是最佳解。
對於 SpecBDD 而言,可能會去描述某個 Class 在呼叫某些函式時 shouldReturn()
、shoudlBe()
或 shouldThrow()
。
它會把該函式行為寫成一個敘事句,以下範例來自 PHPSpec 的官方範例:
// File: src/Markdown.php
class Markdown
{
public function toHtml(string $markdown): string
{
// 事實上,請不要使用這種寫法,這可能會有 XSS 的風險存在
return "<p>$markdown</p>";
}
}
// File: tests/MarkdownTest.php
class MarkdownTest extends ObjectBehavior
{
public function it_converts_plain_text_to_html_paragraphs()
{
return $this->toHtml('Hello World')->shouldReturn('<p>Hello World</p>');
}
}
StoryBDD 則是描述一個整體行為,例如「在輸入帳號及密碼之後,按下 Login,就會登入使用者並且跳轉到 /dashboard
頁面」。
在 PHP 中,通常會用 Behat 這套 Framework 來實現 StoryBDD。
它們會用一個名稱 Gherkin 的語言,這是 BDD 常用於描述行為時使用的語言,因為這個語言的關係讓 BDD 可以抽離程式語言。
DDD,中文譯為「領域驅動開發」。
考量到 TDD 與 BDD 都需要大幅變更測試習慣,可能對於某些業務導向的行業不是這麼友善。
DDD 考量的是「領域」,通常我們會視為「業務」。根據不同的業務分別撰寫其單元測試及整合測試,這有助於讓不同的業務測試被乾淨切分。
舉例來說
$this->login($user)
)今天概述了一些常見的測試,突然覺得好久沒有寫 code 了(遠目)
不過 Modern PHP 的核心一直都不是埋頭寫 code,而是應該在理解概念之後才去寫。
TDD、BDD 或 DDD 都有其優劣存在,不要一味相信某種技術能夠拯救世界 的心態才是最重要的。